package com.lhn;

import org.apache.commons.lang3.time.StopWatch;
import org.junit.Test;

import java.util.concurrent.*;

/**
 * 学习CompletableFuture的案例
 *
 * @author lhn
 * @date 2022/09/02 07:09
 * @since 1.0.0
 **/
public class CompletableFutureDemo1 {

    @Test
    public void testCompletableFutureThenRun() throws Exception {
        StopWatch stopWatch = new StopWatch("执行 thenRun");
        stopWatch.start();
        CompletableFuture <Void> future1 = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        CompletableFuture <Void> future2 = future1.thenRun(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println(future2.get());
        TimeUnit.SECONDS.sleep(3);
        stopWatch.split();
        System.out.printf("%s 耗时一共: %s 秒%n", stopWatch.getMessage(), stopWatch.getSplitTime()/1000);
    }
    /**
     * null
     * 执行 thenRun 耗时一共: 6069
     * */

    @Test
    public void testCompletableFutureThenAccept() throws Exception {
        StopWatch stopWatch = new StopWatch("执行 thenRun");
        stopWatch.start();
        CompletableFuture <Integer> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });
        CompletableFuture <Void> future2 = future1.thenAccept((v) -> {
            try {
                System.out.printf("future1 的返回结果: %s%n", v);
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println(future2.get());
        TimeUnit.SECONDS.sleep(3);
        stopWatch.split();
        System.out.printf("%s 耗时一共: %s 秒%n", stopWatch.getMessage(), stopWatch.getSplitTime()/1000);
    }
    /**
     * future1 的返回结果: 1
     * null
     * 执行 thenRun 耗时一共: 6 秒
     * */

    @Test
    public void testCompletableFutureThenApply() throws Exception {
        StopWatch stopWatch = new StopWatch("执行 thenRun");
        stopWatch.start();
        CompletableFuture <Integer> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        });
        CompletableFuture <Integer> future2 = future1.thenApply((v) -> {
            try {
                System.out.printf("future1 的返回结果: %s%n", v);
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return 10;
        });
        System.out.println(future2.get());
        TimeUnit.SECONDS.sleep(3);
        stopWatch.split();
        System.out.printf("%s 耗时一共: %s 秒%n", stopWatch.getMessage(), stopWatch.getSplitTime()/1000);
    }
    /**
     * future1 的返回结果: 1
     * 10
     * 执行 thenRun 耗时一共: 6 秒
     * */

    @Test
    public void testCompletableFutureWhenCompleted() throws Exception {
        CompletableFuture <Double> future1 = CompletableFuture.supplyAsync(() -> {
            if (ThreadLocalRandom.current().nextDouble() < 0.5) {
                throw new RuntimeException("出错了！");
            }
            return 0.5;
        }).whenComplete((v, e) -> {
            if (v == null) {
                System.out.println("whenComplete aDouble is null");
            } else {
                System.out.println("whenComplete aDouble is " + v);
            }
            if (e == null) {
                System.out.println("whenComplete throwable is null");
            } else {
                System.out.println("whenComplete throwable is " + e.getMessage());
            }
        });
        System.out.println("最终返回的结果 = " + future1.get());
    }

    @Test
    public void testCompletableFutureWhenCompletedExceptionally() throws Exception {
        CompletableFuture <Double> future1 = CompletableFuture.supplyAsync(() -> {
            if (ThreadLocalRandom.current().nextDouble() < 0.5) {
                throw new RuntimeException("出错了！");
            }
            return 0.5;
        }).whenComplete((v, e) -> {
            if (v == null) {
                System.out.println("whenComplete aDouble is null");
            } else {
                System.out.println("whenComplete aDouble is " + v);
            }
            if (e == null) {
                System.out.println("whenComplete throwable is null");
            } else {
                System.out.println("whenComplete throwable is " + e.getMessage());
            }
        }).exceptionally(e ->{
            System.out.println("exceptionally中异常：" + e.getMessage());
            return 0.0;
        });
        System.out.println("最终返回的结果 = " + future1.get());
    }


    @Test
    public void testCompletableThenCombine() throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //开启异步任务1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1，当前线程是：" + Thread.currentThread().getId());
            int result = 1 + 1;
            System.out.println("异步任务1结束");
            return result;
        }, executorService);

        //开启异步任务2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务2，当前线程是：" + Thread.currentThread().getId());
            int result = 1 + 1;
            System.out.println("异步任务2结束");
            return result;
        }, executorService);

        task.runAfterBothAsync(task2, () -> {
            System.out.println("runAfterBoth 无入参无返回值，当前线程是：" + Thread.currentThread().getId());
        },executorService);

        task.thenAcceptBothAsync(task2, (t1, t2) -> {
            System.out.printf("runAfterBoth 有入参：task1入参（%s）task2入参（%s）无返回值，当前线程是：%s%n", t1, t2, Thread.currentThread().getId());
        }, executorService);
        //任务组合
        CompletableFuture<Integer> task3 = task.thenCombineAsync(task2, (t1, t2) -> {
            System.out.printf("thenCombineAsync 有入参：task1入参（%s）task2入参（%s）有返回值，当前线程是：%s%n", t1, t2, Thread.currentThread().getId());
            System.out.println("任务1返回值：" + t1);
            System.out.println("任务2返回值：" + t2);
            return t1 + t2;
        }, executorService);

        Integer res = task3.get();
        System.out.println("最终结果：" + res);
    }


    @Test
    public void testCompletableEitherAsync() throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //开启异步任务1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1，当前线程是：" + Thread.currentThread().getId());

            int result = 1 + 1;
            System.out.println("异步任务1结束");
            return result;
        }, executorService);

        //开启异步任务2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务2，当前线程是：" + Thread.currentThread().getId());
            int result = 1 + 2;
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步任务2结束");
            return result;
        });

        //任务组合
        task.runAfterEitherAsync(task2, () -> {
            System.out.println("执行任务3，当前线程是：" + Thread.currentThread().getId());
        }, executorService);
        //System.out.println(task2.get());
    }

    @Test
    public void testCompletableAallOf() throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //开启异步任务1
        CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务1，当前线程是：" + Thread.currentThread().getId());
            int result = 1 + 1;
            System.out.println("异步任务1结束");
            return result;
        }, executorService);

        //开启异步任务2
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务2，当前线程是：" + Thread.currentThread().getId());
            int result = 1 + 2;
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步任务2结束");
            return result;
        }, executorService);

        //开启异步任务3
        CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("异步任务3，当前线程是：" + Thread.currentThread().getId());
            int result = 1 + 3;
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("异步任务3结束");
            return result;
        }, executorService);

        //任务组合
        CompletableFuture<Void> allOf = CompletableFuture.allOf(task, task2, task3);

        allOf.thenRun(() -> {
            System.out.println("大家都执行完了我再执行！");
        });
        //等待所有任务完成
        allOf.get();
        //获取任务的返回结果
        System.out.println("task结果为：" + task.get());
        System.out.println("task2结果为：" + task2.get());
        System.out.println("task3结果为：" + task3.get());
    }

    @Test
    public void testCompletableAnyOf() throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //开启异步任务1
        CompletableFuture <String> task = CompletableFuture.supplyAsync(() -> {
            return "task1";
        }, executorService);

        //开启异步任务2
        CompletableFuture <String> task2 = CompletableFuture.supplyAsync(() -> {
            return "task2";
        }, executorService);

        //开启异步任务3
        CompletableFuture <String> task3 = CompletableFuture.supplyAsync(() -> {
            return "task3";
        }, executorService);

        //任务组合
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(task, task2, task3);

        anyOf.thenAcceptAsync((v) -> {
            System.out.printf("%s 执行完成了，我也可以执行了！", v);
        });
    }

    @Test
    public void test() throws Exception {
        System.out.println(ThreadLocalRandom.current().nextDouble());
    }
}